<template>
  <ZForm
    :fields="courseFields"
    :initial-values="courseData"
    :schema="courseSchema"
    @submit="onSubmit"
  >
    <div class="flex gap-1 justify-end">
      <ZButton
        class="mt-2"
        color="secondary"
        icon-class="icon-[mdi--restart] size-6"
        type="reset"
      >
        重置
      </ZButton>
      <ZButton
        class="mt-2"
        color="primary"
        icon-class="icon-[mdi--content-save] size-6"
        type="submit"
        :loading="isLoading"
      >
        保存
      </ZButton>
    </div>
  </ZForm>
</template>

<script setup lang="ts">
import { ref, watch, toRaw } from "vue";
import { z } from "zod";
import { ZForm, type FormFields } from "@/components/form";
import ZButton from "@/components/ui/ZButton.vue";

import type { SubmissionContext } from "vee-validate";
import type { Course } from "@/stores";
import { type ApiResponse } from "@/apis";

import { useMutation, useQueryCache } from "@pinia/colada";
import {
  createCourse,
  updateCourse,
  type CreateCourseData,
} from "@/apis/course";
import {
  COURSE_QUERY_KEY,
  useFindCourses,
  findCoursesOptions,
} from "@/query/course";

const props = defineProps<{
  initValues?: Course;
}>();

const emit = defineEmits<{
  success: [Course];
}>();
const nowYear = new Date().getFullYear();
const courseSchema = z.object({
  name: z
    .string()
    .min(2, "课程名称至少2个字符")
    .max(32, "课程名称最多32个字符"),
  teacher: z.string().max(16, "教师名称最多16个字符"),
  classroom: z.string().max(32, "教室名称最多32个字符"),
  semester: z
    .number()
    .int()
    .positive("学年必须为正整数")
    .min(nowYear - 3, `学年必须大于等于${nowYear - 3}`)
    .max(nowYear, `学年必须小于等于${nowYear}`),
  term: z
    .number()
    .int()
    .min(1, `学期必须大于等于1`)
    .max(2, `学期必须小于等于2`),
  nature: z.string().max(8, "课程性质最多8个字符").optional(),
});

const courseFields: FormFields = [
  {
    name: "name",
    label: "课程名称",
    type: "text",
    inputAttributes: {
      placeholder: "课程名称(不是书本名称)",
    },
  },
  {
    name: "teacher",
    label: "教师名称",
    type: "text",
    inputAttributes: {
      placeholder: "请按照课表上教师名字填写",
    },
  },
  [
    {
      name: "classroom",
      label: "教室名称",
      type: "text",
      inputAttributes: {
        placeholder: "请按照课表上教室名字填写",
      },
    },
    {
      name: "semester",
      label: "学年",
      type: "number",
    },
    {
      name: "term",
      label: "学期",
      type: "number",
    },
  ],
  {
    name: "nature",
    label: "课程性质",
    type: "select",
    options: [
      {
        label: "考试",
        value: "考试",
      },
      {
        label: "考察",
        value: "考察",
      },
    ],
  },
];
const initValues = {
  name: "",
  teacher: "",
  classroom: "",
  semester: nowYear,
  term: 1,
  nature: "考试",
};
const courseData = ref<Partial<Course>>(initValues);

watch(
  () => props.initValues,
  (value) => {
    if (value) {
      courseData.value = value;
    } else {
      courseData.value = initValues;
    }
  },
  {
    immediate: true,
  }
);

// 实现乐观更新 (optimistic updates)
const queryCache = useQueryCache();
const { pageParams } = useFindCourses();

const { isLoading, mutateAsync } = useMutation({
  mutation: (data: CreateCourseData) =>
    props.initValues?.id
      ? updateCourse(props.initValues.id, data)
      : createCourse(data),
  onMutate: (data) => {
    const rawPageParams = toRaw(pageParams.value);
    const oldData =
      queryCache.getQueryData(findCoursesOptions(rawPageParams).key) ??
      ({ query: { results: [] as Course[] } } as ApiResponse<Course>);
    // 获取 id
    const id =
      props.initValues?.id ??
      Math.max(...oldData.query.results.map((i) => i.id)) + 1;
    //
    const newData = props.initValues?.id
      ? {
          ...oldData,
          query: {
            ...oldData?.query,
            results: oldData.query.results.map((i) =>
              i.id === props.initValues?.id ? { ...i, ...data } : i
            ),
          },
        }
      : {
          ...oldData,
          query: {
            ...oldData?.query,
            results: [...oldData.query.results, { ...data, id } as Course],
          },
        };
    // 设置缓存
    queryCache.setQueryData(findCoursesOptions(rawPageParams).key, newData);

    return { oldData, newData, id };
  },
  onError(_error, _vars, context) {
    // 回滚数据
    queryCache.setQueryData<ApiResponse<Course>>(
      COURSE_QUERY_KEY.list(pageParams.value),
      context.oldData!
    );
  },
  onSuccess(data) {
    // queryCache.setQueryData<ApiResponse<Course>>(
    //   COURSE_QUERY_KEY.list(pageParams.value),
    //   {
    //     ...context.newData,
    //     query: {
    //       ...context.newData?.query,
    //       results: context.newData.query.results.map((i) =>
    //         i.id === context.id ? { ...i, ...data.object } : i
    //       ),
    //     },
    //   }
    // );
    // 过期课程的所有分页数据
    if (data.success) {
      queryCache.invalidateQueries({
        key: COURSE_QUERY_KEY.root,
      });
    }
    //
    // pageParams.value.page = 1;
  },
});

async function onSubmit(
  values: z.infer<typeof courseSchema>,
  { resetForm, setErrors }: SubmissionContext
) {
  const data = await mutateAsync(values);

  if (data?.success) {
    // 重置表单
    if (!props.initValues) resetForm();
    emit("success", data.object);
  } else {
    // 设置错误信息
    if (data?.errors) setErrors(data.errors);
  }
}
</script>
